package com.jzo2o.health.handler;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.jzo2o.api.trade.RefundRecordApi;
import com.jzo2o.api.trade.dto.response.ExecutionResultResDTO;
import com.jzo2o.api.trade.enums.RefundStatusEnum;
import com.jzo2o.common.constants.UserType;
import com.jzo2o.health.constant.RedisConstants;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.model.domain.Orders;
import com.jzo2o.health.model.domain.OrdersCancelled;
import com.jzo2o.health.model.domain.OrdersRefund;
import com.jzo2o.health.properties.OrdersJobProperties;
import com.jzo2o.health.service.IOrdersRefundService;
import com.jzo2o.health.service.IOrdersService;
import com.jzo2o.redis.helper.CacheHelper;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 订单相关定时任务
 *
 * @author itcast
 * @create 2023/9/2 16:44
 **/
@Slf4j
@Component
public class OrdersHandler {

    @Resource
    private RefundRecordApi refundRecordApi;
    //解决同级方法调用，事务失效问题
    @Resource
    private OrdersHandler orderHandler;
    @Resource
    private IOrdersRefundService ordersRefundService;
    @Resource
    private OrdersJobProperties ordersJobProperties;
    @Resource
    private IOrdersService ordersService;
    @Resource
    private CacheHelper cacheHelper;

    /**
     * 支付超时取消订单
     * 每分钟执行一次
     */
    @XxlJob(value = "cancelOverTimePayOrder")
    public void cancelOverTimePayOrder() {
        // 分片参数
        int shardIndex = NumberUtil.max(XxlJobHelper.getShardIndex(), 0);
        int shardTotal = NumberUtil.max(XxlJobHelper.getShardTotal(), 1);

        //查询支付超时状态订单
        Integer overTimePayOrderCount = ordersJobProperties.getOverTimePayOrderCount();
        List<Orders> ordersList = ordersService.queryOverTimePayOrdersListByCount(overTimePayOrderCount);
        if (CollUtil.isEmpty(ordersList)) {
            XxlJobHelper.log("查询到订单列表为空！shardIndex = {}, shardTotal = {}", shardIndex, shardTotal);
            return;
        }

        for (Orders orders : ordersList) {
            //筛选符合该分片的订单
            if (orders.getId() % shardTotal != shardIndex) {
                continue;
            }

            //清除订单缓存
            String key = String.format(RedisConstants.ORDER_PAGE_QUERY, orders.getMemberId());
            cacheHelper.remove(key);

            //取消订单
            OrdersCancelled ordersCancelled = new OrdersCancelled();
            ordersCancelled.setId(orders.getId());
            ordersCancelled.setCancellerType(UserType.SYSTEM);
            ordersCancelled.setCancelTime(LocalDateTime.now());
            ordersCancelled.setCancelReason("订单超时支付，自动取消");
            ordersService.cancel(orders.getId(), ordersCancelled);
        }
    }

    /**
     * 订单退款异步任务
     */
    @XxlJob(value = "handleRefundOrders")
    public void handleRefundOrders() {
        // 分片参数
        int shardIndex = NumberUtil.max(XxlJobHelper.getShardIndex(), 0);
        int shardTotal = NumberUtil.max(XxlJobHelper.getShardTotal(), 1);

        //查询退款中订单
        Integer refundOrderCount = ordersJobProperties.getRefundOrderCount();
        List<OrdersRefund> ordersRefundList = ordersRefundService.queryRefundOrderListByCount(refundOrderCount);
        if (CollUtil.isEmpty(ordersRefundList)) {
            XxlJobHelper.log("查询到退款订单列表为空！shardIndex = {}, shardTotal = {}", shardIndex, shardTotal);
            return;
        }

        for (OrdersRefund ordersRefund : ordersRefundList) {
            //筛选符合该分片的订单
            if (ordersRefund.getId() % shardTotal != shardIndex) {
                continue;
            }

            //调用第三方进行退款
            ExecutionResultResDTO executionResultResDTO = null;
            try {
                executionResultResDTO = refundRecordApi.refundTrading(ordersRefund.getTradingOrderNo(), ordersRefund.getRealPayAmount());
            } catch (Exception e) {
                log.info("调用第三方退款失败");
            }
            if (executionResultResDTO != null) {
                //退款后处理订单相关信息
                orderHandler.refundOrder(ordersRefund.getId(), executionResultResDTO);
            }

        }
    }

    /**
     * 订单退款处理
     *
     * @param id                    订单id
     * @param executionResultResDTO 第三方退款信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void refundOrder(Long id, ExecutionResultResDTO executionResultResDTO) {
        //根据响应结果更新支付状态
        int payStatus = OrderPayStatusEnum.REFUNDING.getStatus();//退款中
        if (ObjectUtil.equal(RefundStatusEnum.SUCCESS.getCode(), executionResultResDTO.getRefundStatus())) {
            //退款成功
            payStatus = OrderPayStatusEnum.REFUND_SUCCESS.getStatus();
        } else if (ObjectUtil.equal(RefundStatusEnum.FAIL.getCode(), executionResultResDTO.getRefundStatus())) {
            //退款失败
            payStatus = OrderPayStatusEnum.REFUND_FAIL.getStatus();
        }

        //如果是退款中状态，程序结束
        if (ObjectUtil.equal(payStatus, OrderPayStatusEnum.REFUNDING.getStatus())) {
            return;
        }

        //非退款中状态，更新订单的退款状态
        ordersService.updateRefundStatus(id, payStatus, executionResultResDTO.getRefundId(), executionResultResDTO.getRefundNo());

        //非退款中状态，删除申请退款记录，删除后定时任务不再扫描
        ordersRefundService.removeById(id);
    }
}
